/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at

* http://www.apache.org/licenses/LICENSE-2.0

* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.

* File sample_process.cpp
* Description: handle acl resource
*/
#include "inference.h"

#include <sys/timeb.h>

#include <algorithm>
#include <cmath>
#include <iostream>

#include "AclLiteApp.h"
#include "AclLiteModel.h"
#include "CarParams.h"
#include "acl/acl.h"

using namespace std;

namespace {
const char* kDetectModelPath = "../model/MEMD.om";
const int kInvalidSize = -1;
}  // namespace

InferenceThread::InferenceThread(aclrtRunMode& runMode)
    : detectModel_(kDetectModelPath), runMode_(runMode) {
  imageInfoSize_ = 0;
  imageInfoBuf_ = nullptr;
}

InferenceThread::~InferenceThread() { detectModel_.DestroyResource(); }

AclLiteError InferenceThread::InitModelInput() { return ACLLITE_OK; }

AclLiteError InferenceThread::Init() {
  AclLiteError ret = detectModel_.Init();
  if (ret != ACLLITE_OK) {
    ACLLITE_LOG_ERROR("detect Model init failed, error:%d", ret);
    return ret;
  }

  ret = InitModelInput();
  if (ret != ACLLITE_OK) {
    ACLLITE_LOG_ERROR("Model Input init failed, error:%d", ret);
    return ret;
  }

  return ACLLITE_OK;
}

AclLiteError InferenceThread::DetectModelExecute(
    shared_ptr<CarDetectDataMsg> carDetectDataMsg) {
  if (carDetectDataMsg->isLastFrame == 1) {
    ACLLITE_LOG_INFO("it is channel %d's lastframe in Detect Inference",
                     carDetectDataMsg->channelId);
    return ACLLITE_OK;
  }

  AclLiteError ret =
      detectModel_.CreateInput(carDetectDataMsg->resizedFrame.data.get(),
                               carDetectDataMsg->resizedFrame.size);
  if (ret != ACLLITE_OK) {
    ACLLITE_LOG_ERROR("Create detect model input dataset failed");
    return ACLLITE_ERROR;
  }

  ret = detectModel_.Execute(carDetectDataMsg->detectInferData);
  if (ret != ACLLITE_OK) {
    ACLLITE_LOG_ERROR("Execute detect model inference failed, error: %d", ret);
    return ACLLITE_ERROR;
  }
  detectModel_.DestroyInput();

  return ACLLITE_OK;
}

AclLiteError InferenceThread::DetectMsgSend(
    shared_ptr<CarDetectDataMsg> carDetectDataMsg) {
  while (1) {
    AclLiteError ret = SendMessage(carDetectDataMsg->detectPostThreadId,
                                   MSG_DETECT_INFER_OUTPUT, carDetectDataMsg);
    if (ret == ACLLITE_ERROR_ENQUEUE) {
      usleep(500);
      continue;
    } else if (ret == ACLLITE_OK) {
      break;
    } else {
      ACLLITE_LOG_ERROR("Send read frame message failed, error %d", ret);
      return ret;
    }
  }

  return ACLLITE_OK;
}

AclLiteError InferenceThread::Process(int msgId, shared_ptr<void> data) {
  switch (msgId) {
    case MSG_DETECT_PREPROC_DATA:
      DetectModelExecute(static_pointer_cast<CarDetectDataMsg>(data));
      DetectMsgSend(static_pointer_cast<CarDetectDataMsg>(data));
      break;

    default:
      ACLLITE_LOG_INFO("Inference thread ignore msg %d", msgId);
      break;
  }

  return ACLLITE_OK;
}
